package main

import (
	"bytes"

	"code.google.com/p/gochess/movement"
	"code.google.com/p/gochess/notation/epd"
	pos "code.google.com/p/gochess/position"
	"code.google.com/p/gochess/search"
	stats "code.google.com/p/gochess/statistics"

	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"runtime/pprof"
)

func showUsage() {
	fmt.Fprintf(os.Stderr, "usage: ./run_epd_suite -f filename -d n -t n [-h] [-pv] [-stats] [-ttsize n] [-cpuprofile filename]\n")
	flag.PrintDefaults()
}

// mate test:
// http://talkchess.com/forum/viewtopic.php?topic_view=threads&p=500020&t=46665
func main() {
	fmt.Printf("start address of transposition table: %p\n", &search.Transpositions)
	searchDepth := flag.Uint("d", 0, "search depth")
	timeForMove := flag.Duration("t", 0, "time for one move; examples: 200ms, 10s, 1h10m, 1.5h")
	ttSizeMB := flag.Uint("ttsize", search.TTDefaultSize, "size (in MB) of the transposition table (will be rounded down to a power of 2)")
	epdFile := flag.String("f", "", "file name with epd positions")
	printPV := flag.Bool("pv", false, "print principal variations")
	printStats := flag.Bool("stats", false, "print overall statistics")
	cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file")
	usage := flag.Bool("h", false, "show help")

	flag.Usage = showUsage
	flag.Parse()

	if *usage {
		showUsage()
		os.Exit(1)
	}

	if *epdFile == "" {
		showUsage()
		os.Exit(2)
	}

	if *timeForMove == 0 && *searchDepth == 0 {
		showUsage()
		os.Exit(2)
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Printf("could not create file %s\n", *cpuprofile)
			os.Exit(1)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	var searchFlags uint32
	if *printPV {
		searchFlags |= search.PrintPV
	}
	content, err := ioutil.ReadFile(*epdFile)
	if err != nil {
		log.Fatal(err)
	}

	var failures, successes int
	search.Transpositions.Resize(int(*ttSizeMB))
	search.Transpositions.Clear()
	stats.ClearStatistics()
	stats.StartTimer()
	for i, line := range bytes.Split(content, []byte("\n")) {
		line = bytes.TrimSpace(line)
		if len(line) == 0 || line[0] == '#' {
			// skip comments and empty lines
			continue
		}
		position, err := epd.ParsePosition(string(line))
		if err != nil {
			log.Printf("Error in line %v: %v", i, err)
			continue
		}
		epdPosition, err := epd.ParseOperations(position, string(line),
			movement.GenerateLegalMoves(position))
		if err != nil {
			log.Printf("Error in line %v: %v", i, err)
			continue
		}
		move, score := search.Run(position, pos.NoMove, *timeForMove, int32(*searchDepth), searchFlags)

		result := "failure"
		if epdPosition.Operation.IsOk(move) {
			result = "success"
			successes++
		} else {
			failures++
		}
		fmt.Printf("%v: %v %v, computed: %v, score: %d [%s]\n",
			epdPosition.ID, epdPosition.Operation.Name(),
			epdPosition.Operation.Value(), move, score, result)
		if *printPV {
			fmt.Println()
		}
	}
	stats.StopTimer()
	fmt.Printf("\nsuccesses: %v, failures: %v, success rate: %v %%\n",
		successes, failures, successes*100/(failures+successes))
	if *printStats {
		stats.PrintStatistics()
	}
}
